package org.zhuzx.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import org.springframework.util.Assert;

import java.util.Map;

/**
 * 返回结果的通用格式封装，以code=0为成功标志，以Object存放额外数据体data。<br>
 * 若需要解析或者返回复杂的data格式，可以使用新的{@link GenericResult}泛型类，其data为泛型对象。<br>
 * 本类适用于普通的增删改这类的交互场景，只需要知道结果成功与否。
 * @author zhuzx 2022/5/5
 */
@ApiModel("通用返回格式")
public class Result extends GenericResult<Object> {

	/** 基于json字符串构建时，用于存储三个基本字段之外的其它字段值。*/
	@JSONField(serialize = false)
	@JsonIgnore
	private JSONObject otherFields;

	protected Result() {}

	public Result(int code, String msg) {
		super(code, msg);
	}

	public static Result newSuccessResult() {
		return new Result(SUCCESS_CODE_VALUE, SUCCESS_MSG_VALUE);
	}

	public static Result newSuccessResult(String msg) {
		return new Result(SUCCESS_CODE_VALUE, msg);
	}

	public static Result newFailResult(String msg) {
		return new Result(FAIL_CODE_VALUE, msg);
	}

	/**
	 * 根据标志位返回对应的成功或失败的结果对象，可以传入业务错误文本errMsg参数用于详细描述失败的情况。
	 * @param isSuccess 是否成功
	 * @param errMsg 当success为false时将用到这个参数
	 */
	public static Result newResult(boolean isSuccess, String errMsg) {
		return isSuccess ? newSuccessResult() : newFailResult(errMsg);
	}

	/**
	 * 解析远程接口返回的json字符串，得到一个对象。
	 */
	public static Result parseResult(String responseJson) {
		JSONObject map = JSON.parseObject(responseJson);
		Result result = new Result();
		Object code = map.remove("code");
		assertCodeExistAndTypeMatched(code);
		result.code = (Integer) code;
		result.msg = (String) map.remove("msg");
		result.data = map.remove("data");
		if (map.size() > 0) {
			result.otherFields = map;
		}
		result.originalJson = responseJson;
		return result;
	}
	
	@Override
	public Result assertSuccess(String bizErrMsgPrefix) {
		super.assertSuccess(bizErrMsgPrefix);
		return this;
	}

	/**
	 * 从data字段中提取一个任意嵌套深度的值转化为指定类型的对象
	 */
	@SuppressWarnings("unchecked")
	public <T> T extractObjectFromData(Class<T> cla, String... keys) {
		Assert.isTrue(data instanceof Map, "data值并非Map类型，无法提取。");
		return SecondaryUtil.extractObject((Map<String,Object>) data, cla, keys);
	}

	@Override
	public Result setData(Object data) {
		this.data = data;
		return this;
	}

	public Object getObjectValue(String key) {
		return otherFields == null ? null : otherFields.get(key);
	}

	public String getStringValue(String key) {
		return otherFields == null ? null : GeneralUtil.toString(otherFields.get(key));
	}

	public Integer getIntValue(String key) {
		return otherFields == null ? null : (Integer) otherFields.get(key);
	}

}